#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <semaphore.h>

const unsigned int max_cap = 10;

template <typename T>
class RingQueue {
private:
    void P(sem_t& sem) {
        sem_wait(&sem);
    }

    void V(sem_t& sem) {
        // 对 sem 进行加加，也就是释放对应的一个sem
        sem_post(&sem);
    }
public:
    RingQueue(unsigned int cap = max_cap) 
        : _max_cap(cap),
          _ringqueue(cap),
          _c_step(0),
          _p_step(0)
    {
        // 初始情况下的空间状态为满，但数据状态为0
        sem_init(&_space_sem, 0, cap);
        sem_init(&_data_sem, 0, 0);
        pthread_mutex_init(&_c_mutex, nullptr);
        pthread_mutex_init(&_p_mutex, nullptr);
    }

    void Pop(T* out) {
        // 先上锁
        // Pop出一个数据，空间量加一，数据量减一
        // 信号量的申请需要在抢锁之前，因为信号量的申请可以同时多线程到原子的信号量
        // 而抢锁只有一个线程能抢到，其他线程只能等待
        P(_data_sem);
        pthread_mutex_lock(&_c_mutex);
        *out = _ringqueue[_c_step];
        _c_step++;
        _c_step %= _max_cap;
        pthread_mutex_unlock(&_c_mutex);
        V(_space_sem);
    }

    void Push(const T& in) {
        // push 进入一个数据，数据量加一，空间量减一
        P(_space_sem);
        pthread_mutex_lock(&_p_mutex);
        _ringqueue[_p_step] = in;
        _p_step++;
        _p_step %= _max_cap;
        pthread_mutex_unlock(&_p_mutex);
        V(_data_sem);
    }


    ~RingQueue() {
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);
        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }
private:    
    std::vector<T> _ringqueue;
    unsigned int _max_cap;
    unsigned int _c_step;
    unsigned int _p_step;
    sem_t _space_sem;
    sem_t _data_sem;

    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
};